#include "gd32w51x.h"
#include "stdint.h"
#include "stdio.h"
#include "version.h"
#include "DevicesDelay.h"
#include "DevicesADC.h"

static uint16_t st_usADC1DmaDatas[ADC1_SAMPLING_NUMBER][ADC1_SAMPLING_CHANNEL] = {0};


void vADCInit(void)
{
    /* enable GPIOC clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOC);
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC);

    /* config ADC clock */
    adc_clock_config(ADC_ADCCK_HCLK_DIV6);


    /* config the GPIO as analog mode */
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1);


    /* ADC continuous function enable */
    adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC scan function enable */
    adc_special_function_config(ADC_SCAN_MODE, ENABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC1_SAMPLING_CHANNEL);


    /* ADC regular channel config */
    adc_regular_channel_config(0, ADC_SAMPLE_BATTERY_CHARGING_CURRENT,  ADC_SAMPLE_TIME);
    adc_regular_channel_config(1, ADC_SAMPLE_BATTERY_VOLTAGE,           ADC_SAMPLE_TIME);
    adc_regular_channel_config(2, ADC_SAMPLE_WHEEL_LEFT_CURRENT,        ADC_SAMPLE_TIME);
    adc_regular_channel_config(3, ADC_SAMPLE_WHEEL_RIGHT_CURRENT,       ADC_SAMPLE_TIME);
    adc_regular_channel_config(4, ADC_SAMPLE_BRUSH_SIDE_CURRENT,        ADC_SAMPLE_TIME);
    adc_regular_channel_config(5, ADC_SAMPLE_BRUSH_MIDDLE_CURRENT,      ADC_SAMPLE_TIME);


    /* ADC trigger config */
    // adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_SWRCST);
    adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);

    /* enable ADC interface */
    adc_enable();
    /* wait for ADC stability */
    vDelayMs(10.0f);


    vADCDMAInit();


    /* ADC software trigger enable */
    adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}

void vADCDMAInit(void)
{
    /* ADC_DMA_channel configuration */
    dma_single_data_parameter_struct dma_init_struct = {0};

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA1);

    /* deinitialize DMA channel1 */
    dma_deinit(DMA1, DMA_CH4);
    /* initialize DMA single data mode */
    dma_init_struct.periph_addr           = (uint32_t)(&ADC_RDATA);
    dma_init_struct.periph_inc            = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory0_addr          = (uint32_t)st_usADC1DmaDatas;
    dma_init_struct.memory_inc            = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width   = DMA_PERIPH_WIDTH_16BIT;
    dma_init_struct.circular_mode         = DMA_CIRCULAR_MODE_ENABLE;
    dma_init_struct.direction             = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.number                = ADC1_SAMPLING_NUMBER * ADC1_SAMPLING_CHANNEL;
    dma_init_struct.priority              = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1, DMA_CH4, &dma_init_struct);

    /* DMA channel peripheral select */
    dma_channel_subperipheral_select(DMA1, DMA_CH4, DMA_SUBPERI0);

    /* enable DMA channel */
    dma_channel_enable(DMA1, DMA_CH4);

    /* ADC DMA function enable */
    adc_dma_request_after_last_enable();
    adc_dma_mode_enable();
}

/*!
    \brief      ADC dma channel
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetDMAValue(uint8_t ucChannel)
{
    uint32_t uiValueSum = 0;
    uint16_t *pDatasHand = (uint16_t *)st_usADC1DmaDatas;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF, i = 0;

    if(ucChannel >= ADC1_SAMPLING_CHANNEL)
        return 0.0f;

    pDatasHand += ucChannel;

    for(i = 0; i < ADC1_SAMPLING_NUMBER; ++i)
    {
        usValueNow  = *pDatasHand;
        uiValueSum += usValueNow;

        pDatasHand += ADC1_SAMPLING_CHANNEL;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    uiValueSum -= usValueMax + usValueMin;

return ((float)uiValueSum / (ADC1_SAMPLING_NUMBER - 2) * (3300.0f / 4095.0f));
}

/*!
    \brief      ADC channel sample
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetChannelValue(uint8_t channel, uint32_t uiCnt)
{
    uint32_t uiValueSum = 0, i = 0;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF;


    /* ADC regular channel config */
    adc_regular_channel_config(0, channel, ADC_SAMPLE_TIME);


    /* 切换通道后，丢弃第一次转换的数据 */
    /* wait the end of conversion flag */
    while(!adc_flag_get(ADC_FLAG_EOC));
    /* clear the end of conversion flag */
    adc_flag_clear(ADC_FLAG_EOC);
    /* get regular channel sample value */
    adc_regular_data_read();


    for(i = 0; i < uiCnt; ++i)
    {
        /* wait the end of conversion flag */
        while(!adc_flag_get(ADC_FLAG_EOC));
        /* clear the end of conversion flag */
        adc_flag_clear(ADC_FLAG_EOC);
        /* get regular channel sample value */
        usValueNow = adc_regular_data_read();

        uiValueSum += usValueNow;;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }


    /* 去除最大与最小值 */
    uiValueSum -= (usValueMax + usValueMin);

    return ((float)uiValueSum / (uiCnt - 2) * (3300.0f / 4095.0f));
}
